package com.docted.design.pattern.proxy.dynamic.customer;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author DoCted
 * @since v1.0 2018/3/11
 */
public class DocProxy {


    public static final String br = "\r\n";


    public static Object newProxyInstance(DocClassLoader classLoader, Class<?>[] interfaces, DocInvocationHandler h) {


        try {
            //1.动态生成源代码.java
            String javaSrc = generateJavaSrc(interfaces);


            //2.把.java文件输出到磁盘
            String filePath = DocProxy.class.getResource("").getPath();
            System.out.println(filePath);
            File file = new File(filePath + "$Proxy0.java");
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(javaSrc);
            fileWriter.flush();
            fileWriter.close();

            //3.把生成的.java编程成.class
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(file);

            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();

            //4.把编译生成的.class加载到JVM
            Class proxyClass = classLoader.findClass("$Proxy0");
            Constructor constructor = proxyClass.getConstructor(DocInvocationHandler.class);
//            file.delete();
            //5.返回字节码重组后的新的代理对象
            return constructor.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }

    private static String generateJavaSrc(Class<?>[] interfaces) {

        StringBuffer sb = new StringBuffer();

        sb.append("package com.docted.design.pattern.proxy.dynamic.customer;" + br);

        sb.append("\r\n");
        sb.append("import java.lang.reflect.Method;" + br);
        sb.append("import com.docted.design.pattern.proxy.dynamic.jdk.Graduate;" + br);

        sb.append("public class $Proxy0 implements " + interfaces[0].getSimpleName() + " {" + br);
        sb.append("DocInvocationHandler h;" + br);
        sb.append("public $Proxy0(DocInvocationHandler h) { " + br);
        sb.append("this.h = h;" + br);
        sb.append("}" + br);

        for (Method method : interfaces[0].getMethods()) {
            sb.append("public " + method.getReturnType() + " " + method.getName() + "() {" + br);
            sb.append("try{" + br);


            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[]{});" + br);
            sb.append("this.h.invoke(this, m, null);" + br);

            sb.append("} catch(Throwable e) {" + br);
            sb.append("e.printStackTrace();" + br);
            sb.append("}" + br);
            sb.append("}" +br);
        }

        sb.append("}" + br);


        return sb.toString();
    }

}
